
package ift605.EquationWithAgent.server.agent;

import ift605.EquationWithAgent.server.EquationMessage;
import ift605.EquationWithAgent.server.MarvinEquation;

import java.io.IOException;
import java.util.Scanner;

import udes.ds.agent.AbstractEquation;
import udes.ds.agent.BasicEquation;
import udes.ds.agent.Constant;
import udes.ds.agent.Equation;
import udes.ds.agent.ExponentialEquation;
import udes.ds.agent.MultiplicativeEquation;
import udes.ds.agent.SimpleExponentialEquation;
import udes.ds.agent.SummativeEquation;
import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.CyclicBehaviour;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;

public class ClientAgent extends Agent {
	private static final long serialVersionUID = 1L;
	protected final String RESULT_ID = "Result";
	protected final String DERIVATE_ID = "Derivate";
	protected String AID_NAME_DERIVATIVE = "Derivative";

	protected void setup() {
		addBehaviour(new ReceiveMessageBehaviour());
		new Thread(new ConsoleReaderThread(this)).start();
	}
	
	private class ReceiveMessageBehaviour extends CyclicBehaviour{
		private static final long serialVersionUID = 1L;

		@Override
		public void action() {
			try
			{
				ACLMessage msg = receive(MessageTemplate.MatchConversationId(RESULT_ID));
				if (msg == null) {
					// if no message is arrived, block the behaviour
					block();
				}
				else {
					// Display the received message
					System.out.println("Reveived from " + msg.getSender().getLocalName());
					EquationMessage mess = (EquationMessage) msg.getContentObject();
					if(mess.getEquation() == null){
						System.out.println("This equation is unknown. Sorry about that :(");
					}
					else {
						System.out.println("-------------------------------------------------" + myAgent.getLocalName()+" RECEIVED DERIVED FORMULA ----------------------------------------------------");
						mess.getEquation().printUserReadable(); 
					}
				}
			}
			catch( Exception e){
				e.printStackTrace();
			}
		}
	}
	
	public class ConsoleReaderThread implements Runnable {
		public final static String DERIVE_REQUEST = "DERIVE_REQUEST";
		ClientAgent clientAgent;
		
		public ConsoleReaderThread(ClientAgent clientAgent) {
			this.clientAgent = clientAgent;
		}

		@Override
		public void run() {
			// always read the console
			while(true){
				try {
					Scanner in = new Scanner(System.in);
				    AbstractEquation eq = GetEquation(in);
				    
				    if(eq == null) {
				    	// terminate thread if the client is destroy
				    	clientAgent.doDelete();
				    	return;
				    }
			    	
				    // Send equation to DerivativeAgent (server)
					ACLMessage msg = new ACLMessage(ACLMessage.REQUEST);
					msg.setConversationId(DERIVATE_ID);
					msg.setContentObject(new EquationMessage(0, eq));
					msg.addReceiver(new AID(AID_NAME_DERIVATIVE, AID.ISLOCALNAME));
					clientAgent.send(msg);

					// Let other process have time to compute
					Thread.sleep(1500);
					
				} catch (IOException e) {
					e.printStackTrace();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
		
		// Transforme the client console input to AbstractEquation
		private AbstractEquation GetEquation(Scanner in)
		{
			AbstractEquation eq = null;
			boolean finished = false;
			while(!finished){
				System.out.println("Choose command :");
				System.out.println("(1) : Polynome < y = Kx^n >");
				System.out.println("(2) : Polynome < y = Kn-1x^(n-1) + ... + K0x^0 >");
				System.out.println("(3) : Polynome < y = f(x)g(x) >");
				System.out.println("(4) : Marvin");
				System.out.println("(5) : Simple Exponential < y = k*e^x >");
				System.out.println("(6) : Exponential <y = k*e^f(x) >");
				System.out.println("(7) : Quit");
				
				int reading= in.nextInt();

				// TODO get list of equation in a list
				switch(reading){
				case 1:
					eq = computeSimplePolynome(in);
					finished = true;
					break;
				case 2:
					eq = computeComplexPolynome(in);
					finished = true;
					break;
				case 3:
					eq = computeMultiplicativPolynome(in);	
					finished = true;
					break;
				case 4:
					eq = new MarvinEquation();
					finished = true;
					break;
				case 5:
					eq = computeSimpleExponential(in);
					finished = true;
					break;
				case 6:
					eq = computeExponential(in);
					finished = true;
					break;
				case 7:
					finished = true;
					break;
				default:
					break;
				}
			}
			
			return eq;
		}

		private AbstractEquation computeMultiplicativPolynome(Scanner in) {
			System.out.println("Choose first equation");
			AbstractEquation eq1 = GetEquation(in);
			AbstractEquation eq2 = null;
			
			if(eq1 != null)
			{
				System.out.println("Choose second equation");
				eq2 = GetEquation(in);
				if(eq2 != null)
				{
					eq2 = new MultiplicativeEquation(eq1, eq2);
				}
			}
			
			return eq2;
		}

		private AbstractEquation computeComplexPolynome(Scanner in) {
			System.out.println("Enter the number of elements your polynome will contain :");
			int n = in.nextInt();

			SummativeEquation eq = new SummativeEquation(new Constant(0), new Constant(0));
			for(int i = n - 1; i > -1; --i)
			{
				Equation temp = computeSimplePolynome(in, i);
				eq = new SummativeEquation((AbstractEquation) temp, eq);
			}
			return eq;
		}

		private AbstractEquation computeSimplePolynome(Scanner in){
			int n = 0;
			
			System.out.println("Enter n value :");
			n = in.nextInt();
			
			return computeSimplePolynome(in,n);
		}
		
		private AbstractEquation computeSimplePolynome(Scanner in, int n){
			System.out.println("Enter K value :");
			int k = in.nextInt();
			
			return new BasicEquation(k,n);
		}
		
		private AbstractEquation computeSimpleExponential(Scanner in){
			System.out.println("Enter K value :");
			double k = in.nextDouble();
			
			return new SimpleExponentialEquation(k);
		}
		
		private AbstractEquation computeExponential(Scanner in){
			System.out.println("Enter K value :");
			double k = in.nextDouble();
			System.out.println("Choose exponent equation");
			AbstractEquation eq1 = GetEquation(in);
			return new ExponentialEquation(k, eq1);
		}
	}
}
